#include "pwm.h"
#include "gpio.h"
#define DEF_DC_HZ 200
uint32_t fm_Period = 1000; // 周期，单位us
uint32_t fm_PosWidth = 1000; // 周期，单位us
uint32_t Period = 200;    // 周期，单位us
uint32_t PosWidth = 20;   // 正脉宽，单位us
void pwm_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    __RCC_GPIOA_CLK_ENABLE();
    __RCC_GPIOB_CLK_ENABLE();
    // 蜂鸣器
    GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = GPIO_PIN_12;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

    GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
    PA12_AFx_GTIM3CH4();
    // pwm输出
    GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = GPIO_PIN_4;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

    GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
    PB04_AFx_GTIM1CH1();
}

void PWM_OutputConfig(void)
{
    GTIM_InitTypeDef GTIM_InitStruct;
    pwm_gpio_init();
    __RCC_GTIM1_CLK_ENABLE();

    GTIM_InitStruct.Mode = GTIM_MODE_TIME;
    GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
    GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV16; // DCLK = PCLK / 16 = 64MHz/16 = 4MHz
    GTIM_InitStruct.ReloadValue = Period - 1;
    GTIM_InitStruct.ToggleOutState = DISABLE;

    GTIM_TimeBaseInit(CW_GTIM1, &GTIM_InitStruct);
    GTIM_OCInit(CW_GTIM1, GTIM_CHANNEL1, GTIM_OC_OUTPUT_PWM_HIGH);
    GTIM_SetCompare1(CW_GTIM1, PosWidth);
    GTIM_ITConfig(CW_GTIM1, GTIM_IT_OV, ENABLE);

    GTIM_Cmd(CW_GTIM1, ENABLE);
    __RCC_GTIM3_CLK_ENABLE();

    GTIM_InitStruct.Mode = GTIM_MODE_TIME;
    GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
    GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV16; // DCLK = PCLK / 16 = 64MHz/16 = 4MHz
    GTIM_InitStruct.ReloadValue = fm_Period - 1;
    GTIM_InitStruct.ToggleOutState = DISABLE;

    GTIM_TimeBaseInit(CW_GTIM3, &GTIM_InitStruct);
    GTIM_OCInit(CW_GTIM3, GTIM_CHANNEL4, GTIM_OC_OUTPUT_PWM_HIGH);
    GTIM_SetCompare4(CW_GTIM3, fm_PosWidth);
    GTIM_ITConfig(CW_GTIM3, GTIM_IT_OV, ENABLE);
    
    GTIM_Cmd(CW_GTIM3, ENABLE);
#ifdef USE_GTIM2
    __RCC_GTIM2_CLK_ENABLE();

    GTIM_InitStruct.Mode = GTIM_MODE_TIME;
    GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
    GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV1; // DCLK = PCLK / 16 = 64MHz/16 = 4MHz
    GTIM_InitStruct.ReloadValue = 64 * 1000 - 1;
    GTIM_InitStruct.ToggleOutState = DISABLE;

    GTIM_TimeBaseInit(CW_GTIM2, &GTIM_InitStruct);
    GTIM_ITConfig(CW_GTIM2, GTIM_IT_OV, ENABLE);
    GTIM_DMAConfig(CW_GTIM2, GTIM_DMA_OV, ENABLE);
    GTIM_Cmd(CW_GTIM2, ENABLE);
#endif // DEBUG USE_GTIM2
    __disable_irq();
    NVIC_EnableIRQ(GTIM1_IRQn);
#ifdef USE_GTIM2
    NVIC_EnableIRQ(GTIM2_IRQn);
#endif // DEBUG USE_GTIM2
    NVIC_EnableIRQ(GTIM3_IRQn);
    __enable_irq();
}
//10% 0.6 ,90% 6v
//y = 0.0647x - 0.019
uint16_t get_dc_val(void)
{
    uint16_t ratio;
    uint16_t ret;
    if (Period != DEF_DC_HZ)
    {
        Period = DEF_DC_HZ;
    }
    ratio = (Period - PosWidth) / 2;
    ret = ratio * 64 - 19;
    if (ret % 100 > 50)
    {
        ret = ret / 100 + 1;
    }
    else
    {
        ret = ret / 100;
    }
    return ret*100;
}
//x=(y+0.019) /0.0647
void set_dc_val(uint16_t val)
{
    uint16_t ratio;
    if (Period != DEF_DC_HZ)
    {
        Period = DEF_DC_HZ;
    }
    ratio = (val + 19) / 64;
    PosWidth = Period - 2 * ratio;
}
uint8_t get_pwm_duty(void)
{
    return (Period - PosWidth) * 100 / Period;
}
void set_pwm_duty(uint8_t duty)
{
    if(duty > 100)
    {
        PosWidth = 0;
    }
    else
    {
        PosWidth = Period - Period * duty/100;
    }
}
uint32_t get_pwm_hz(void)
{
    uint32_t hz;
    hz = 4000000 / Period;
    return hz;
}
void set_pwm_hz(uint32_t hz_val)
{
    Period = 4000000 / hz_val;
    GTIM_SetReloadValue(CW_GTIM1, Period);
}
void set_fm_onoff(uint8_t sta)
{
    if(sta == 1)
    {
        fm_PosWidth = 500;
    }
    else
    {
        fm_PosWidth = 1000;
    }
}
void GTIM1_IRQHandler(void)
{
    static uint16_t TimeCnt = 0;
    GTIM_ClearITPendingBit(CW_GTIM1, GTIM_IT_OV);
    if (TimeCnt++ >= 100)
    {
        TimeCnt = 0;
        GTIM_SetCompare1(CW_GTIM1, PosWidth);
    }
    /* USER CODE END */
}
void GTIM2_IRQHandler(void)
{
    /* USER CODE BEGIN */
    // 中断每500us进入一次，每50ms改变一次PosWidth
    GTIM_ClearITPendingBit(CW_GTIM2, GTIM_IT_OV);
    /* USER CODE END */
}
void GTIM3_IRQHandler(void)
{
    /* USER CODE BEGIN */
    // 中断每500us进入一次，每50ms改变一次PosWidth
    static uint16_t TimeCnt = 0;
    GTIM_ClearITPendingBit(CW_GTIM3, GTIM_IT_OV);
    if (TimeCnt++ >= 100) // 50ms
    {
        TimeCnt = 0;
        GTIM_SetCompare4(CW_GTIM3, fm_PosWidth);
    }
    /* USER CODE END */
}
